#include <QPainter>
#include <QTimer>
// #include <QSound>
#include <QMouseEvent>
#include <QMessageBox>
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QDebug>
#include <math.h>
#include "mainwindow.h"

// 游戏得有点小曲吧,但是有点吵,预留
// #define CHESS_ONE_SOUND ":/res/sound/chessone.wav"
// #define WIN_SOUND ":/res/sound/win.wav"
// #define LOSE_SOUND ":/res/sound/lose.wav"

const int kBoardMargin = 30; // 棋盘边缘空隙
const int kRadius = 15; // 棋子半径
const int kMarkSize = 6; // 落子标记边长
const int kBlockSize = 40; // 格子的大小
const int kPosDelta = 20; // 鼠标点击的模糊距离上限
const int kAIDelay = 700;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // 设置棋盘大小
    setFixedSize(kBoardMargin * 2 + kBlockSize * kBoardSizeNum, kBoardMargin * 2 + kBlockSize * kBoardSizeNum);
    setWindowTitle("五子棋游戏");

    // setStyleSheet("background-color:yellow;");

    // 开启鼠标hover功能，这两句一般要设置window的
    setMouseTracking(true);
//    centralWidget()->setMouseTracking(true);

    // 添加菜单
    // 游戏菜单
    QMenu *gameMenu = menuBar()->addMenu(tr("游戏(&G)"));

    // 游戏模式子菜单
    QMenu *modeMenu = gameMenu->addMenu(tr("游戏模式"));
    QAction *actionPVP = new QAction(tr("双人对战(&P)"), this);
    actionPVP->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_P));
    connect(actionPVP, SIGNAL(triggered()), this, SLOT(initPVPGame()));
    modeMenu->addAction(actionPVP);

    QAction *actionPVE = new QAction(tr("人机对战(&C)"), this);
    actionPVE->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_C));
    connect(actionPVE, SIGNAL(triggered()), this, SLOT(initPVEGame()));
    modeMenu->addAction(actionPVE);

    gameMenu->addSeparator(); // 分隔线

    // 悔棋功能
    QAction *actionUndo = new QAction(tr("悔棋(&Z)"), this);
    actionUndo->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Z));
    connect(actionUndo, SIGNAL(triggered()), this, SLOT(undoMove()));
    gameMenu->addAction(actionUndo);

    gameMenu->addSeparator(); // 分隔线

    // 退出游戏
    QAction *actionExit = new QAction(tr("退出(&X)"), this);
    actionExit->setShortcut(QKeySequence::Quit);
    connect(actionExit, SIGNAL(triggered()), this, SLOT(close()));
    gameMenu->addAction(actionExit);

    // 帮助菜单
    QMenu *helpMenu = menuBar()->addMenu(tr("帮助(&H)"));
    QAction *actionAbout = new QAction(tr("关于(&A)"), this);
    connect(actionAbout, SIGNAL(triggered()), this, SLOT(showAbout()));
    helpMenu->addAction(actionAbout);

    // 开始游戏
    initGame();
}

MainWindow::~MainWindow()
{
    if (game)
    {
        delete game;
        game = nullptr;
    }
}

/**
 * @brief 初始化游戏
 * 
 * 1. 创建GameModel对象实例
 * 2. 默认启动人机对战模式
 * 3. 设置游戏初始状态
 */
void MainWindow::initGame()
{
    // 初始化游戏模型
    game = new GameModel;
    initPVEGame(); // 默认启动人机对战模式
}

void MainWindow::initPVPGame()
{
    type = PERSON;
    game->status = PLAYING;
    game->start(type);
    update();
}

void MainWindow::initPVEGame()
{
    type = BOT;
    game->status = PLAYING;
    game->start(type);
    update();
}

/**
 * @brief 绘制游戏界面
 * @param event 绘制事件
 * 
 * 功能说明：
 * 1. 绘制15x15的棋盘网格
 * 2. 绘制当前鼠标位置的落子提示标记
 * 3. 绘制已落子的黑白棋子
 * 4. 检查并显示游戏胜负状态
 * 5. 使用抗锯齿技术提高绘制质量
 */
void MainWindow::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    // 绘制棋盘
    painter.setRenderHint(QPainter::Antialiasing, true); // 抗锯齿
//    QPen pen; // 调整线条宽度
//    pen.setWidth(2);
//    painter.setPen(pen);
    for (int i = 0; i < kBoardSizeNum + 1; i++)
    {
        painter.drawLine(kBoardMargin + kBlockSize * i, kBoardMargin, kBoardMargin + kBlockSize * i, size().height() - kBoardMargin);
        painter.drawLine(kBoardMargin, kBoardMargin + kBlockSize * i, size().width() - kBoardMargin, kBoardMargin + kBlockSize * i);
    }

    QBrush brush;
    brush.setStyle(Qt::SolidPattern);
    // 绘制落子标记(防止鼠标出框越界)
    if (row > 0 && row < kBoardSizeNum &&
        col > 0 && col < kBoardSizeNum &&
        game->map[row][col] == 0)
    {
        if (game->player)
            brush.setColor(Qt::white);
        else
            brush.setColor(Qt::black);
        painter.setBrush(brush);
        painter.drawRect(kBoardMargin + kBlockSize * col - kMarkSize / 2, kBoardMargin + kBlockSize * row - kMarkSize / 2, kMarkSize, kMarkSize);
    }

    // 绘制棋子 
    for (int i = 0; i < kBoardSizeNum; i++)
        for (int j = 0; j < kBoardSizeNum; j++)
        {
            if (game->map[i][j] == 1)
            {
                brush.setColor(Qt::white);
                painter.setBrush(brush);
                painter.drawEllipse(kBoardMargin + kBlockSize * j - kRadius, kBoardMargin + kBlockSize * i - kRadius, kRadius * 2, kRadius * 2);
            }
            else if (game->map[i][j] == -1)
            {
                brush.setColor(Qt::black);
                painter.setBrush(brush);
                painter.drawEllipse(kBoardMargin + kBlockSize * j - kRadius, kBoardMargin + kBlockSize * i - kRadius, kRadius * 2, kRadius * 2);
            }
        }

    // 判断输赢
    if (row > 0 && row < kBoardSizeNum &&
        col > 0 && col < kBoardSizeNum &&
        (game->map[row][col] == 1 ||
            game->map[row][col] == -1))
    {
        if (game->isWin(row, col) && game->status == PLAYING)
        {
            qDebug() << "win";
            game->status = WIN;
            // QSound::play(WIN_SOUND);
            QString str;
            if (game->map[row][col] == 1)
                str = "white player";
            else if (game->map[row][col] == -1)
                str = "black player";
            QMessageBox::StandardButton btnValue = QMessageBox::information(this, "congratulations", str + " win!");

            // 重置游戏状态，否则容易死循环
            if (btnValue == QMessageBox::Ok)
            {
                game->start(type);
                game->status = PLAYING;
            }
        }
    }


    // 判断死局
    if (game->isDeadGame())
    {
        // QSound::play(LOSE_SOUND);
        QMessageBox::StandardButton btnValue = QMessageBox::information(this, "oops", "dead game!");
        if (btnValue == QMessageBox::Ok)
        {
            game->start(type);
            game->status = PLAYING;
        }

    }
}


/**
 * @brief 鼠标落子
 * 
 * 1.确保鼠标点击后五子棋落在有效范围之内
 * 2.修正鼠标点击误差范围,使落子符合点击预期
 * 3.存储落子坐标,重绘棋盘
 */
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{   
    // 通过鼠标的hover确定落子的标记
    int x = event->x();
    int y = event->y();

    // 棋盘边缘不能落子
    if (x >= kBoardMargin + kBlockSize / 2 &&
            x < size().width() - kBoardMargin &&
            y >= kBoardMargin + kBlockSize / 2 &&
            y < size().height()- kBoardMargin)
    {
        // 获取最近的左上角的点
        int tmpCol = x / kBlockSize;
        int tmpRow = y / kBlockSize;

        int leftTopPosX = kBoardMargin + kBlockSize * tmpCol;
        int leftTopPosY = kBoardMargin + kBlockSize * tmpRow;

        // 根据距离算出合适的点击位置,一共四个点，根据半径距离选最近的
        row = -1; // 初始化
        col = -1;
        int len = 0; // 计算完后取整

        // 确定一个误差范围内的点,补充修正
        // 计算到四个顶点的距离
        len = sqrt((x - leftTopPosX) * (x - leftTopPosX) + (y - leftTopPosY) * (y - leftTopPosY));
        if (len < kPosDelta)
        {
            row = tmpRow;
            col = tmpCol;
        }
        len = sqrt((x - leftTopPosX - kBlockSize) * (x - leftTopPosX - kBlockSize) + (y - leftTopPosY) * (y - leftTopPosY));
        if (len < kPosDelta)
        {
            row = tmpRow;
            col = tmpCol + 1;
        }
        len = sqrt((x - leftTopPosX) * (x - leftTopPosX) + (y - leftTopPosY - kBlockSize) * (y - leftTopPosY - kBlockSize));
        if (len < kPosDelta)
        {
            row = tmpRow + 1;
            col = tmpCol;
        }
        len = sqrt((x - leftTopPosX - kBlockSize) * (x - leftTopPosX - kBlockSize) + (y - leftTopPosY - kBlockSize) * (y - leftTopPosY - kBlockSize));
        if (len < kPosDelta)
        {
            row = tmpRow + 1;
            col = tmpCol + 1;
        }

        // 确保落子范围有效
        if (row >= 0 && row < kBoardSizeNum && col >= 0 && col < kBoardSizeNum) {
            qDebug() << "Selected position: (" << row << "," << col << ")";
        } else {
            row = -1;
            col = -1;
        }
    }

    // 存储后重绘
    update();
}

/**
 * @brief   确保只有一方落子(不枪子)
 * 
 */
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    // 人下棋，并且不能抢机器的棋
    if (!(game->type == BOT && !game->player))
    {
        chessOneByPerson();
        // 如果是人机模式，需要调用AI下棋
        if (game->type == BOT && !game->player)
        {
            // 用定时器做一个延迟
            QTimer::singleShot(kAIDelay, this, SLOT(chessOneByAI()));
        }
    }

}

void MainWindow::chessOneByPerson()
{
    // 根据当前存储的坐标下子
    // 只有有效点击才下子，并且该处没有子
    if (row != -1 && col != -1 && game->map[row][col] == 0)
    {
        game->playerMove(row, col);
        // QSound::play(CHESS_ONE_SOUND);
        

        // 重绘
        update();
    }
}

void MainWindow::chessOneByAI()
{
    game->aiMove(row, col);
    // QSound::play(CHESS_ONE_SOUND)

    update();
}
